Question on writing to log file
The code that I am running writes data to an external text Log file. There are a number of functions within this code that write to this Log file. Issue is that the Log file is not written to properly in that it appears that the data written to by one file overwrites that of another file. What also is confusing me is that the data that I expect to be written 1st is written last. For example, the Main section of the code writes 10 lines to the Log file and one of the following executed functions writes 20 lines. What shows up in the log appears to be the 20 lines of code from the 2nd write operation, except that the 1st 10 lines are from the 1st write (i.e., the 1st 10 lines of the Log file are as expected, but the 11th line is not the start of the 2nd write operation (the new 20 lines of text), but rather it starts at line 11 of the 20 lines if text that was written in). I tried using the Append command instead of the Write command and results do not look as expected. The following code is used. Any suggestions?
Stream writetoFile
function 1 writetofile = write (outputfilename) writetofile = write (outputfilename) writetoFile << "Log file comment"
function 2 writetofile = write (outputfilename) writetoFile << "Log file comment"
Main writetofile = write (outputfilename) writetoFile << "Log file comment" Mike.P.Adams - Mon Feb 16 12:28:28 EST 2015 |
Re: Writing to a Log file Hi, Get rid of all the writetofile = write(outputfilename) except the one in Main. The write (filename) is what actually makes the output file and starts the stream. From there on, when you want to write to the file, you just write to the stream using the << command. It's also good practice to close the stream at the end. Hope this helps, Greg |
Re: Writing to a Log file GregM_dxler - Mon Feb 16 12:45:17 EST 2015 Hi, Get rid of all the writetofile = write(outputfilename) except the one in Main. The write (filename) is what actually makes the output file and starts the stream. From there on, when you want to write to the file, you just write to the stream using the << command. It's also good practice to close the stream at the end. Hope this helps, Greg thanks, Geg - making those changes worked! |
Re: Writing to a Log file Mike.P.Adams - Mon Feb 16 14:17:05 EST 2015 thanks, Geg - making those changes worked! In case of a log file you should use flus(wirteofile) to make shure that the data is really stored. Otherwise the dxl script can crash and the log file may not contain the important very last data ... |
Re: Writing to a Log file One more hint regarding logfiles: Do NOT try to "append" to the log file. While there is a perm for this, the problem is, that this perm leaks an object (Stream) in memory every time you call it, and this can make your DXL become extremely slow after a couple of 1000 leaks. Regards, Mathias |
Re: Writing to a Log file Mathias Mamsch - Tue Feb 17 10:47:09 EST 2015 One more hint regarding logfiles: Do NOT try to "append" to the log file. While there is a perm for this, the problem is, that this perm leaks an object (Stream) in memory every time you call it, and this can make your DXL become extremely slow after a couple of 1000 leaks. Regards, Mathias HI, Can you clarify what you mean by "append"? and how big of a memory leak this is and what versions of Doors it impacts? |
Re: Writing to a Log file WardEdwards - Wed Feb 18 09:04:29 EST 2015 HI, Can you clarify what you mean by "append"? and how big of a memory leak this is and what versions of Doors it impacts? By append I mean the perm: Stream append (string) or any other of the Stream perms: Stream read (string) Stream read (string, int) Stream read (Binary__) Stream write (string) Stream write (string, int) Stream write (Binary__) Stream append (Binary__) Stream append (string, int) Stream openpictfile (Object) Stream openPictFile (Object) Note that up to DOORS 9.6 there is no "delete (Stream)" perm, which means, once a file is opened the Stream object will stay alive forever. There is a "close(Stream)" perm, but that perm will only close the file, but not free the stream object (as it should). To test this, run the following code:
pragma runLim, 0
// Adapt this count, start small until you get reasoable times
int GCOUNT = 30000 // adapt if times are to low / hight for your computer
int steps = 1000;
void performWork () {
Buffer buf = create();
delete buf;
}
void profile (string sMsg, int count, void func ()) {
int iStart = getTickCount_ ();
int i; for (i = 0; i < count; i++) func();
int iEnd = getTickCount_ ();
print sMsg ": " (iEnd - iStart) " ms \n"
}
string sFilename = "C:\\temp\\test.txt";
int allocations = 0;
profile ("Before allocations: ", GCOUNT , performWork)
for (allocations = steps; allocations < 20000; allocations += steps) {
// Leak 1000 objects here ...
int x; for (x = 0; x < steps; x++) {
// Comment me out and the leak goes away...
Stream strm = append(sFilename); close strm;
}
profile ("After " allocations " allocations: ", GCOUNT , performWork)
}
You will probably get something like this: Before allocations: : 47 ms After 1000 allocations: : 328 ms After 2000 allocations: : 577 ms After 3000 allocations: : 858 ms After 4000 allocations: : 1170 ms After 5000 allocations: : 1514 ms After 6000 allocations: : 1794 ms After 7000 allocations: : 2121 ms After 8000 allocations: : 2418 ms After 9000 allocations: : 2683 ms After 10000 allocations: : 2964 ms After 11000 allocations: : 3276 ms After 12000 allocations: : 3557 ms After 13000 allocations: : 3838 ms After 14000 allocations: : 4150 ms After 15000 allocations: : 4461 ms After 16000 allocations: : 4648 ms After 17000 allocations: : 4961 ms After 18000 allocations: : 5226 ms After 19000 allocations: : 5553 ms Which means, that after writing 20000 lines of log, your DXL might have slowed down by the factor of 100 (!!). To see that this is really about the allocations of the streams, just comment out the Stream line. You will get no increase. This topic has been disussed a lot in the forum. Just search for memory slow down leak, etc. You will find code to test for these kind of memory leaks. Regards, Mathias |
Re: Writing to a Log file Mathias Mamsch - Wed Feb 18 09:40:46 EST 2015 By append I mean the perm: Stream append (string) or any other of the Stream perms: Stream read (string) Stream read (string, int) Stream read (Binary__) Stream write (string) Stream write (string, int) Stream write (Binary__) Stream append (Binary__) Stream append (string, int) Stream openpictfile (Object) Stream openPictFile (Object) Note that up to DOORS 9.6 there is no "delete (Stream)" perm, which means, once a file is opened the Stream object will stay alive forever. There is a "close(Stream)" perm, but that perm will only close the file, but not free the stream object (as it should). To test this, run the following code:
pragma runLim, 0
// Adapt this count, start small until you get reasoable times
int GCOUNT = 30000 // adapt if times are to low / hight for your computer
int steps = 1000;
void performWork () {
Buffer buf = create();
delete buf;
}
void profile (string sMsg, int count, void func ()) {
int iStart = getTickCount_ ();
int i; for (i = 0; i < count; i++) func();
int iEnd = getTickCount_ ();
print sMsg ": " (iEnd - iStart) " ms \n"
}
string sFilename = "C:\\temp\\test.txt";
int allocations = 0;
profile ("Before allocations: ", GCOUNT , performWork)
for (allocations = steps; allocations < 20000; allocations += steps) {
// Leak 1000 objects here ...
int x; for (x = 0; x < steps; x++) {
// Comment me out and the leak goes away...
Stream strm = append(sFilename); close strm;
}
profile ("After " allocations " allocations: ", GCOUNT , performWork)
}
You will probably get something like this: Before allocations: : 47 ms After 1000 allocations: : 328 ms After 2000 allocations: : 577 ms After 3000 allocations: : 858 ms After 4000 allocations: : 1170 ms After 5000 allocations: : 1514 ms After 6000 allocations: : 1794 ms After 7000 allocations: : 2121 ms After 8000 allocations: : 2418 ms After 9000 allocations: : 2683 ms After 10000 allocations: : 2964 ms After 11000 allocations: : 3276 ms After 12000 allocations: : 3557 ms After 13000 allocations: : 3838 ms After 14000 allocations: : 4150 ms After 15000 allocations: : 4461 ms After 16000 allocations: : 4648 ms After 17000 allocations: : 4961 ms After 18000 allocations: : 5226 ms After 19000 allocations: : 5553 ms Which means, that after writing 20000 lines of log, your DXL might have slowed down by the factor of 100 (!!). To see that this is really about the allocations of the streams, just comment out the Stream line. You will get no increase. This topic has been disussed a lot in the forum. Just search for memory slow down leak, etc. You will find code to test for these kind of memory leaks. Regards, Mathias Note that by the way, you can circumvent these kinds of leaks by using "eval" ... If you need to use the Stream perms a lot! Regards, Mathias |
Re: Writing to a Log file Mathias Mamsch - Wed Feb 18 09:40:46 EST 2015 By append I mean the perm: Stream append (string) or any other of the Stream perms: Stream read (string) Stream read (string, int) Stream read (Binary__) Stream write (string) Stream write (string, int) Stream write (Binary__) Stream append (Binary__) Stream append (string, int) Stream openpictfile (Object) Stream openPictFile (Object) Note that up to DOORS 9.6 there is no "delete (Stream)" perm, which means, once a file is opened the Stream object will stay alive forever. There is a "close(Stream)" perm, but that perm will only close the file, but not free the stream object (as it should). To test this, run the following code:
pragma runLim, 0
// Adapt this count, start small until you get reasoable times
int GCOUNT = 30000 // adapt if times are to low / hight for your computer
int steps = 1000;
void performWork () {
Buffer buf = create();
delete buf;
}
void profile (string sMsg, int count, void func ()) {
int iStart = getTickCount_ ();
int i; for (i = 0; i < count; i++) func();
int iEnd = getTickCount_ ();
print sMsg ": " (iEnd - iStart) " ms \n"
}
string sFilename = "C:\\temp\\test.txt";
int allocations = 0;
profile ("Before allocations: ", GCOUNT , performWork)
for (allocations = steps; allocations < 20000; allocations += steps) {
// Leak 1000 objects here ...
int x; for (x = 0; x < steps; x++) {
// Comment me out and the leak goes away...
Stream strm = append(sFilename); close strm;
}
profile ("After " allocations " allocations: ", GCOUNT , performWork)
}
You will probably get something like this: Before allocations: : 47 ms After 1000 allocations: : 328 ms After 2000 allocations: : 577 ms After 3000 allocations: : 858 ms After 4000 allocations: : 1170 ms After 5000 allocations: : 1514 ms After 6000 allocations: : 1794 ms After 7000 allocations: : 2121 ms After 8000 allocations: : 2418 ms After 9000 allocations: : 2683 ms After 10000 allocations: : 2964 ms After 11000 allocations: : 3276 ms After 12000 allocations: : 3557 ms After 13000 allocations: : 3838 ms After 14000 allocations: : 4150 ms After 15000 allocations: : 4461 ms After 16000 allocations: : 4648 ms After 17000 allocations: : 4961 ms After 18000 allocations: : 5226 ms After 19000 allocations: : 5553 ms Which means, that after writing 20000 lines of log, your DXL might have slowed down by the factor of 100 (!!). To see that this is really about the allocations of the streams, just comment out the Stream line. You will get no increase. This topic has been disussed a lot in the forum. Just search for memory slow down leak, etc. You will find code to test for these kind of memory leaks. Regards, Mathias Better is to compare two versions which writes data to the file
pragma runLim, 0// Adapt this count, start small until you get reasoable times
int GCOUNT = 30000 // adapt if times are to low / hight for your computer
int steps = 1000;
bool bUseWrite = false; // Change from false to true to use append ...
void performWork () {
Buffer buf = create();
delete buf;
}
void profile (string sMsg, int count, void func ()) {
int iStart = getTickCount_ ();
int i;
for (i = 0; i < count; i++) func();
int iEnd = getTickCount_ ();
print sMsg ": " (iEnd - iStart) " ms \n"
}
string sFilename = "C:\\temp\\test.txt";
int allocations = 0;
profile ("Before allocations: ", GCOUNT , performWork);
Stream strmWrite;
if (bUseWrite) {
strmWrite = write(sFilename);
}
for (allocations = steps; allocations < 20000; allocations += steps) {
// Leak 1000 objects here ...
int x;
for (x = 0; x < steps; x++) {
if (bUseWrite) {
strmWrite << "123\n";
flush(strmWrite);
} else {
// Comment me out and the leak goes away...
Stream strm = append(sFilename);
strm << "123\n";
close strm;
}
}
profile ("After " allocations " allocations: ", GCOUNT , performWork)
}
|
Re: Writing to a Log file Wolfgang Uhr - Wed Feb 18 11:55:11 EST 2015 Better is to compare two versions which writes data to the file
pragma runLim, 0// Adapt this count, start small until you get reasoable times
int GCOUNT = 30000 // adapt if times are to low / hight for your computer
int steps = 1000;
bool bUseWrite = false; // Change from false to true to use append ...
void performWork () {
Buffer buf = create();
delete buf;
}
void profile (string sMsg, int count, void func ()) {
int iStart = getTickCount_ ();
int i;
for (i = 0; i < count; i++) func();
int iEnd = getTickCount_ ();
print sMsg ": " (iEnd - iStart) " ms \n"
}
string sFilename = "C:\\temp\\test.txt";
int allocations = 0;
profile ("Before allocations: ", GCOUNT , performWork);
Stream strmWrite;
if (bUseWrite) {
strmWrite = write(sFilename);
}
for (allocations = steps; allocations < 20000; allocations += steps) {
// Leak 1000 objects here ...
int x;
for (x = 0; x < steps; x++) {
if (bUseWrite) {
strmWrite << "123\n";
flush(strmWrite);
} else {
// Comment me out and the leak goes away...
Stream strm = append(sFilename);
strm << "123\n";
close strm;
}
}
profile ("After " allocations " allocations: ", GCOUNT , performWork)
}
I find it easier to save the data to a buffer and then save it to the file at the end instead of trying to write it as I go. Doesn't this reduce the problem? That way the outputting to a file is compartmentalize and it also seems to let the script run faster. Greg |
Re: Writing to a Log file GregM_dxler - Thu Feb 19 08:54:33 EST 2015 I find it easier to save the data to a buffer and then save it to the file at the end instead of trying to write it as I go. Doesn't this reduce the problem? That way the outputting to a file is compartmentalize and it also seems to let the script run faster. Greg well, yes, but if your script crashes for whatever reasons, your log file will never be written and you don't have any information on why or where your script crashed (and IMO that's one of the main reasons for creating log files) |